use std::iter;

// Option can be viewed as a container that contains either zero or one element.
// In particular, it implements the IntoIterator trait, and as such can be used
// with generic code that needs such a type.
fn main() {
    {
        let turing = Some("Turing");
        let mut logicians = vec!["Curry", "Kleene", "Markov"];

        logicians.extend(turing);
        assert_eq!(vec!["Curry", "Kleene", "Markov", "Turing"], logicians);
    }

    {
        let turing = Some("Turing");
        let mut logicians = vec!["Curry", "Kleene", "Markov"];

        if let Some(turing_inner) = turing {
            logicians.push(turing_inner);
        }
        assert_eq!(vec!["Curry", "Kleene", "Markov", "Turing"], logicians);
    }

    {
        let turing = Some("Turing");
        let logicians = ["Curry", "Kleene", "Markov"];

        for logician in logicians.iter().chain(turing.iter()) {
            println!("{logician} is a logician");
        }
    }

    {
        let mut one = iter::once(1);

        assert_eq!(Some(1), one.next());
        assert_eq!(None, one.next());
    }

    {
        let mut logicians = vec!["Curry", "Kleene", "Markov"];

        logicians.extend(iter::once("Turing"));
        assert_eq!(vec!["Curry", "Kleene", "Markov", "Turing"], logicians);
    }

    {
        let logicians = ["Curry", "Kleene", "Markov"];

        for logician in logicians.iter().chain(iter::once("Turing").next().iter()) {
            println!("{logician} is a logician");
        }
    }

    {
        let items = ["1", "two", "NaN", "four", "5"];

        let mut iter = items.iter().filter_map(|x| x.parse::<i32>().ok());
        assert_eq!(iter.next(), Some(1));
        assert_eq!(iter.next(), Some(5));
        assert_eq!(iter.next(), None);

        let mut iter = items.iter().flat_map(|x| x.parse::<i32>());
        assert_eq!(iter.next(), Some(1));
        assert_eq!(iter.next(), Some(5));
        assert_eq!(iter.next(), None);
    }
}
